﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2022   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-UL84BU5
 * 公司名称：
 * 命名空间：KingerRobot.WanliMDC.Biz
 * 唯一标识：24249019-4b0e-43cf-9e67-c03a7e5c182c
 * 文件名：LineBiz
 * 当前用户域：DESKTOP-UL84BU5
 * 
 * 创建者：zzl
 * 电子邮箱：1003590782@qq.com
 * 创建时间：2022/9/7 13:14:05
 * 版本：V1.0.0
 * 描述：出库线体扫描
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>


using System.Threading.Tasks;

namespace KingerRobot.MexicoSailunMDC.Biz;

/// <summary>
/// 出库线体扫描任务
/// </summary>
internal class ExLineScannerBiz : K8.MDCBB.Biz
{
    private const string ClassName = nameof(TemplateBiz);
    #region 配置参数
    private ParamData Param { get; set; }

    class ParamData
    {
        /// <summary>
        /// 扫描仪设备ID
        /// </summary>
        public long LineScannerId { get; set; }
        /// <summary>
        /// 扫描仪位置ID
        /// </summary>
        public long LineScannerLoc { get; set; }
        /// <summary>
        /// 线体编号
        /// </summary>
        public string StationNo { get; set; }
        /// <summary>
        /// 扫描仪名称
        /// </summary>
        public string LineScannerName { get; set; }
    }
    #endregion

    #region PLC 通讯参数
    private ValueData Data { get; set; }
    class ValueData
    {
        /// <summary>
        /// 线体产品条码
        /// </summary>
        public string ProductCode { get; set; }
        ///// <summary>
        ///// 产品条码（扫描条码，写条码）
        ///// </summary>
        //public string SProductCode { get; set; }
        /// <summary>
        /// 流水号（读）
        /// </summary>
        public int? RWorkNo { get; set; }
        /// <summary>
        /// 0:PLC读取后可改成 0
        /// 1:WCS任务下传完成..............可读可写/WCS读取到 0，下发任务，PLC接收到 1，改为 0。
        /// </summary>
        public int TaskFlag { get; set; }
        /// <summary>
        /// 目标位
        /// </summary>
        public string Destination { get; set; }
        /// <summary>
        /// 条码是否正确
        /// </summary>
        public int RBarCodeStatus { get; set; }
    }
    #endregion

    #region 缓存
    private CacheData Cache { get; set; }
    class CacheData
    {
        /// <summary>
        /// 条码
        /// </summary>
        public string ProductCode { get; set; }

        /// <summary>
        /// 出库扫描后流水号
        /// </summary>
        public int ScannerTaskNo { get; set; }
        ///// <summary>
        ///// 条码
        ///// </summary>
        //public string SProductCode { get; set; }
    }
    #endregion

    #region 实时日志
    private StepData Step { get; set; }
    class StepData
    {
        private string _msg = string.Empty;
        public string StepMsg
        {
            get
            {
                return this._msg;
            }
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    this._msg = string.Empty;
                    return;
                }
                this._msg = $"{ClassName}|{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}>>{value}";
            }
        }
    }
    private void StepMsg(string msg)
    {
        this.Step.StepMsg = msg;
    }
    #endregion

    #region 文件日志（运行需要 Nlog 配置）
    private void WriteLog(string message)
    {
        K8.LSF.Client.Log(new K8.LSF.Log { Data = message });
    }
    #endregion

    /// <summary>
    /// 和 PLC 通讯对象
    /// </summary>
    private BizData BizData { get; set; }
    public int Execute(BizData writer)
    {
        // Excute 方法外使用 BizData
        this.BizData = writer;

        // 返回参数
        var result = 0;
        if (Data.TaskFlag == (int)EnumLineAck.WCSDownFinish)
        {
            // 已扫描条码
            this.StepMsg($" {Data.RWorkNo}任务下传完成，但PLC未读取成功:{Data.TaskFlag}【PLC读取后可改成 0】");
            return result;
        }

        if (String.IsNullOrWhiteSpace(Data.ProductCode))
        {
            this.StepMsg($"条码不存在");
            return result;
        }
        if (Data.ProductCode.Contains(ConstFields.Default) || Data.ProductCode.Contains(ConstFields.NoRead))
        {
            this.StepMsg($"条码不存在");
            return result;
        }

        // 获取任务信息
        var taskService = K8.RSF.Client.Create<ITaskService>();
        //如果线体判断条码相同 则数据库修改此线体任务已扫描过 防止后面的重复任务号(过冲、手动等导致)导致正常任务被删除
        if (Data.RBarCodeStatus == 0)
        {
            // 已扫描条码
            this.StepMsg($"条码{Data.ProductCode} 正确");
            WriteLog($"条码{Data.ProductCode} 正确");
            var taskNo = Data.RWorkNo;

            if (Cache.ScannerTaskNo == taskNo)
            {
                this.StepMsg($"条码{Data.ProductCode} 正确,任务已被记录");
                return result;
            }

            var count = taskService.UpdateTaskIsOutScannerByTaskNo(taskNo ?? 0);
            if (count > 0)
            {
                Cache.ScannerTaskNo = taskNo ?? 0;
                Cache.ProductCode = Data.ProductCode;
            }
            return result;
        }

        WriteLog($"出库扫描条码不正确{Data.ToJson()}");
        this.StepMsg($"出库扫描条码不正确{Data.ToJson()}");

        // 线体条码
        var productCode = Data.ProductCode;
        if (string.IsNullOrWhiteSpace(productCode) || ConstFields.Default.StartsWith(productCode))
        {
            WriteLog($"线体条码为空");
            this.StepMsg($"线体条码为空.");
            return result;
        }

        if (productCode.StartsWith(ConstFields.NoRead))
        {
            WriteLog($"线体条码为 NOREAD.");
            this.StepMsg($"线体条码为 NOREAD.");
            return result;
        }

        //// 出库扫描条码
        //var sProductCode = Value.SProductCode;
        //if (string.IsNullOrWhiteSpace(sProductCode))
        //{
        //    this.StepMsg($"扫描条码为空.");
        //    return result;
        //}
        //if (sProductCode.StartsWith(ConstFields.NoRead))
        //{
        //    sProductCode = ConstFields.NoRead;
        //}


        // 是否执行
        if (productCode == Cache.ProductCode)
        {
            WriteLog($"{productCode} 已执行.");
            this.StepMsg($"{productCode} 已执行.");
            return result;
        }

        // 条码不相同创建异常
        var exWarehousingScan = K8.RSF.Client.Create<IExWarehousingAfterScanService>();
        var taskId = exWarehousingScan.CreateTask(Param.LineScannerLoc, productCode, Data.RWorkNo.GetValueOrDefault(), string.Empty, Data.Destination);
        if (taskId == 0)
        {
            this.StepMsg($"条码:{productCode} 线体流水号:{Data.RWorkNo} 创建任务失败：{taskId}");
            //WriteLog($"条码:{Value.ToJson()}  线体流水号:{Value.RWorkNo} 创建任务失败：{taskId}");
            return result;
        }

        //// TODO 已经是一场任务可以考虑删除
        //if (taskId == 1)
        //{
        //    // 异常任务下传
        //    ExecuteCmd(new()
        //    {
        //        TargetPlcLoc = Value.Destination,
        //        TaskNo = Value.RWorkNo,
        //    }, taskId, productCode, string.Empty);

        //    return result;
        //}
        //如果这次读到的和上次写入的一致 就把上次写入的清零
        if (taskId == -1)
        {
            SetProductCode();
            return result;
        }



        var task = taskService.GetTaskByTaskId(taskId);
        if (task is null)
        {

            this.StepMsg($"{taskId},未获取数据");
            WriteLog($"条码:{productCode} {taskId},未获取数据");
            return result;
        }

        // 下发
        ExecuteCmd(task, taskId, productCode, string.Empty);

        return result;
    }

    private void ExecuteCmd(BizTaskBean task, long taskId, string productCode, string sProductCode)
    {
        if (task.OutSize == 0)
        {
            task.OutSize = 500;
        }

        var mark = SetTaskInfo(task, productCode);
        WriteLog($"条码{productCode}，下发结果{mark}");
        WriteLog($"条码{productCode}，{taskId}，目标地址{task.TargetCmdPlcLoc},流水号{task.TaskNo},OutSize{task.OutSize},下发结果{mark}");
        this.StepMsg($"{taskId}，目标地址{task.TargetCmdPlcLoc},流水号{task.TaskNo},OutSize{task.OutSize},下发结果{mark}");
        if (mark <= 0)
        {
            return;
        }

        // 任务下传完成，修改标识
        mark = this.SetTaskFlag();
        if (mark <= 0)
        {
            return;
        }

        // 执行、保存缓存
        var taskNo = task.TaskNo.GetValueOrDefault();

        if (taskNo != 0)
        {
            var service = K8.RSF.Client.Create<IExWarehousingAfterScanService>();
            var excute = service.ExecuteTask(taskNo, Param.LineScannerLoc);
            WriteLog($"流水号{taskNo}执行结果{excute}");
            if (excute <= 0)
            {
                return;
            }
        }
        //执行成功后变为默认值 暂时注释
        //SetClearInfo();

        Cache.ProductCode = productCode;

        // Cache.SProductCode = sProductCode;
    }

    private int SetTaskInfo(BizTaskBean task, string productCode)
    {
        //var code = sProductCode?.Chunk(2).ToList();

        return this.BizData.WriteData(new
        {
            Destination = task.TargetCmdPlcLoc,        // 目标地址
            WorkNo = task.TaskNo,                   // 流水号
            OutSize = task.OutSize,
            SProductCode = productCode,
            //SProductCode01 = GetProductItem(code, 1),
            //SProductCode02 = GetProductItem(code, 2),
            //SProductCode03 = GetProductItem(code, 3),
            //SProductCode04 = GetProductItem(code, 4),
            //SProductCode05 = GetProductItem(code, 5),
        });
    }

    /// <summary>
    /// 获取拆分条码
    /// </summary>
    /// <param name="codes"></param>
    /// <param name="ind">从1开始</param>
    /// <returns></returns>
    private string GetProductItem(List<char[]> codes, int ind)
    {
        if (codes.Count >= ind)
        {
            return new string(codes[ind - 1]);
        }
        return string.Empty;
    }

    private int SetTaskFlag()
    {
        var mark = this.BizData.WriteData(new
        {
            TaskFlag = EnumLineAck.WCSDownFinish,
        });
        Thread.Sleep(100);
        return mark;
    }
    private int SetProductCode()
    {
        var mark = this.BizData.WriteData(new
        {
            SProductCode = ConstFields.Default
        });
        Thread.Sleep(100);
        return mark;
    }


    private int SetClearInfo()
    {
        return this.BizData.WriteData(new
        {
            Destination = 0,        // 目标地址
            WorkNo = 0,                   // 流水号
            OutSize = 0,
            SProductCode = ConstFields.Default,

        });
    }
}
